package org.mtmi.ui.controls.curve;

import java.util.ArrayList;

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.mtmi.ui.drawables.IDrawable;
import org.mtmi.ui.scenes.COLOR;

/**
 * A value transformer based on polynomial curve defining y=f(x) function.
 *
 */
public class CurveValueTransformer implements IValueTransformer
{

	private class Image implements IDrawable
	{

		@Override
		public Point computeSize(int width, int height) {
			return new Point( 32, 32 );
		}

		@Override
		public void paint( GC gc, int x, int y, int width, int height, int state )
		{
			int xy[] = new int[ 2*points.size() ];
			
			int iw=0;
			for( int i=0; i<points.size(); i++ ) {
				FPoint p = points.get( i );
				xy[iw++] = x + Math.round( width*p.x() );
				xy[iw++] = y + height - Math.round( height*p.y() );
			}
			
			int lc = gc.getLineCap();
			int lj = gc.getLineJoin();
			gc.setLineCap( SWT.CAP_ROUND );
			gc.setLineJoin( SWT.JOIN_ROUND );
			gc.setLineWidth(4);
			if( state == SELECTED ) {
				gc.setForeground( COLOR.light_blue );
			} else {
				gc.setForeground( COLOR.dark_blue );
			}
			gc.drawPolyline( xy );
			gc.setLineWidth(2);
			gc.setForeground( COLOR.blue );
			gc.drawPolyline( xy );
			gc.setLineCap( lc );
			gc.setLineJoin( lj );
		}
	}
	

	private ArrayList<FPoint> points; //must have at least 2 points
	private Image image;
	
	public CurveValueTransformer()
	{
		//by default define identity:
		points = new ArrayList<FPoint>();
		points.add( new FPoint( 0,0 ) );
		points.add( new FPoint( 1,1 ) );
	}
	
	/** made for CurveManager only */
	CurveValueTransformer( ArrayList<FPoint> pts )
	{
		points = pts;
	}
	
	@Override
	public IDrawable getDrawable() {
		if( image==null ) image=new Image();
		return image;
	}
	
	/** provide access to points FOR EDITOR ONLY */
	ArrayList<FPoint> getPoints() { return points; }

	@Override
	public float transformValue( float input )
	{
		for( int i=1; i<points.size(); i++ ) {
			FPoint b = points.get( i );
			if( b.x() >= input ) {
				FPoint a = points.get( i-1 );
				if( b.x()==a.x() ) {
					return a.y(); //a choice, this is a vertical line
				} else {
					float y = (b.y()-a.y())*(input-a.x())/(b.x()-a.x()) + a.y();
					return y;
				}
			}
		}
		return 0; //by default but means input >1, forbidden !!
	}
	
	/** reset curve to identify function */
	public void reset() {
		points.clear();
		points.add( new FPoint( 0, 0 ) );
		points.add( new FPoint( 1, 1 ) );
	}
	
	/** reset curve to reverse function (1 for input=0, to 0 when input is 1) */
	public void resetReverse() {
		points.clear();
		points.add( new FPoint( 0, 1 ) );
		points.add( new FPoint( 1, 0 ) );
	}

	/** modify curve by applying a vertical swap of points */
	public void swapV() {
		for( int i=0; i<points.size(); i++ ) {
			FPoint p = points.get( i );
			p.setY( 1-p.y() );
		}
	}
	
	/** modify curve by applying an horizontal swap of points */
	public void swapH() {
		ArrayList<FPoint> rev = new ArrayList<FPoint>();
		for( int i=0; i<points.size(); i++ ) {
			FPoint p = points.get( i );
			p.setX( 1-p.x() );
			rev.add( 0, points.get( i ) );
		}
		points = rev;
		//to be sure:
		points.get( 0 ).setX( 0 );
		points.get( points.size()-1 ).setX( 1 );
	}
	
}
